package com.hj.payment.service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.hj.common.exception.BusinessException;
import com.hj.common.util.ServletUtils;
import com.hj.common.util.UUIDUtils;
import com.hj.payment.common.config.AliPayApiConfig;
import com.hj.payment.common.pojo.AliPayRefundVO;
import com.hj.payment.common.pojo.AliPayVO;
import com.hj.payment.common.pojo.AliTradePayVO;
import com.hj.payment.common.properties.AliPayProperties;
import com.hj.payment.service.AliPayService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Service
public class AliPayServiceImpl implements AliPayService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final String CHARSET = "UTF-8";//编码
    private static final Integer ORDERNUMBER = 16;//订单号位数
    private static final String EXPIRE = "30m";//交易多长时间后关闭

    @Autowired
    private AliPayProperties aliPayProperties;

    @Autowired
    private AliPayApiConfig aliPayApiConfig;

    /**
     * 电脑网站支付
     *
     * @param aliPayVO
     */
    @Override
    public void pcPay(AliPayVO aliPayVO) {
        logger.info("===========支付宝电脑网站支付============");
        //支付内容参数
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        String current = UUIDUtils.getRandomNumber(ORDERNUMBER);
        logger.info("订单号 : {}", current);
        model.setOutTradeNo(current);//订单号 不可重复
        model.setProductCode("FAST_INSTANT_TRADE_PAY");//销售产品码 电脑网站支付固定为 FAST_INSTANT_TRADE_PAY
        model.setTotalAmount(aliPayVO.getAmount().toString());//商品金额
        model.setSubject("支付宝电脑网站支付");//商品标题
        model.setBody("支付宝支付，共" + aliPayVO.getAmount() + "元");//商品描述
        model.setTimeoutExpress(EXPIRE);//设置订单最晚付款时间  过期交易将关闭
        //构建请求
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setReturnUrl(aliPayProperties.getReturnUrl());
        request.setNotifyUrl(aliPayProperties.getNotyfyUrl());
        request.setBizModel(model);

        //发起请求
        try {
            String form = aliPayApiConfig.getAliPayClient().pageExecute(request).getBody();
            HttpServletResponse response = ServletUtils.getResponse();
            response.setContentType("text/html;charset=" + CHARSET);
            PrintWriter writer = response.getWriter();
            logger.info("调用成功 : {}", form);
            writer.write(form);
            writer.flush();
            writer.close();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝电脑网站支付失败");
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝response对象获取流失败");
        }
    }

    /**
     * app支付
     *
     * @param aliPayVO
     */
    @Override
    public String appPay(AliPayVO aliPayVO) {
        logger.info("===========支付宝APP支付============");
        //支付参数设置
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        String current = UUIDUtils.getRandomNumber(ORDERNUMBER);
        logger.info("订单号 : {}", current);
        model.setOutTradeNo(current);
        model.setSubject("支付宝APP支付");
        model.setTotalAmount(aliPayVO.getAmount().toString());
        model.setBody("支付宝支付，共" + aliPayVO.getAmount() + "元");
        model.setProductCode("QUICK_MSECURITY_PAY");
        model.setTimeoutExpress(EXPIRE);//设置过期时间为30分钟
        model.setPassbackParams("callback params");
        //构建请求
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        request.setReturnUrl(aliPayProperties.getReturnUrl());
        request.setNotifyUrl(aliPayProperties.getNotyfyUrl());
        request.setBizModel(model);
        AlipayTradeAppPayResponse response = null;
        try {
            response = aliPayApiConfig.getAliPayClient().sdkExecute(request);
            logger.info("调用成功 : {}", response.getBody());
            return response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝app支付失败");
        }
    }

    /**
     * 手机网站支付
     *
     * @param aliPayVO
     */
    @Override
    public void WapPay(AliPayVO aliPayVO) {
        logger.info("===========支付宝手机网站支付============");
        //支付内容参数
        AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
        String current = UUIDUtils.getRandomNumber(ORDERNUMBER);
        logger.info("订单号 : {}", current);
        model.setOutTradeNo(current);//订单号 不可重复
        model.setSubject("支付宝手机网站支付");//商品标题
        model.setTotalAmount(aliPayVO.getAmount().toString());//商品金额
        model.setBody("支付宝支付，共" + aliPayVO.getAmount() + "元");//商品描述
        model.setProductCode("QUICK_WAP_PAY");
        model.setTimeoutExpress(EXPIRE);//设置过期时间为30分钟
        //构建请求
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
        request.setReturnUrl(aliPayProperties.getReturnUrl());
        request.setNotifyUrl(aliPayProperties.getNotyfyUrl());
        request.setBizModel(model);
        //发起请求
        try {
            String form = aliPayApiConfig.getAliPayClient().pageExecute(request).getBody();
            HttpServletResponse response = ServletUtils.getResponse();
            response.setContentType("text/html;charset=" + CHARSET);
            logger.info("调用成功 : {}", form);
            PrintWriter out = response.getWriter();
            out.write(form);
            out.flush();
            out.close();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝手机网站支付失败");
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝response对象获取流失败");
        }
    }

    /**
     * 条码 声波支付
     * 注意 : 需要保证authCode的准确性 (即 : 支付付款方的条码转换数据)
     * 否则会返回 <支付失败，获取顾客账户信息失败，请顾客刷新付款码后重新收款，如再次收款失败，请联系管理员处理。> 的信息
     *
     * @param aliTradePayVO
     * @return
     */
    @Override
    public String tradePay(AliTradePayVO aliTradePayVO) {
        logger.info("===========支付宝条码 声波支付============");
        String subject = null;
        String scene = aliTradePayVO.getScene();
        if ("wave_code".equals(scene)) {
            subject = "支付宝声波支付";
        } else if ("bar_code".equals(scene)) {
            subject = "支付宝条形码支付";
        } else {
            throw new BusinessException("入参错误");
        }
        //请求参数
        AlipayTradePayModel model = new AlipayTradePayModel();
        String current = UUIDUtils.getRandomNumber(ORDERNUMBER);
        logger.info("订单号 : {}", current);
        model.setOutTradeNo(current);//商户订单号，需要保证不重复
        model.setScene(scene);//条码支付固定传入 bar_code  声波 wave_code
        model.setAuthCode(aliTradePayVO.getAuthCode());//用户付款码，25-30 开头的长度为 16-24 位的数字，实际字符串长度以开发者获取的付款码长度为准；付款码使用一次即失效
        model.setSubject(subject);//订单标题
        model.setStoreId(aliTradePayVO.getStoreId());//商户门店编号
        model.setTotalAmount(aliTradePayVO.getAmount().toString());
        model.setTimeoutExpress(EXPIRE);//设置过期时间为30分钟
        //构建请求
        AlipayTradePayRequest request = new AlipayTradePayRequest();
        request.setReturnUrl(aliPayProperties.getReturnUrl());
        request.setNotifyUrl(aliPayProperties.getNotyfyUrl());
        request.setBizModel(model);
        try {
            AlipayTradePayResponse response = aliPayApiConfig.getAliPayClient().execute(request);
            logger.info("调用成功 : {}", response.getBody());
            return response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝条码或声波支付失败");
        }
    }

    /**
     * 扫码支付
     *
     * @param aliTradePayVO
     * @return
     */
    @Override
    public String tradePrecreatePay(AliTradePayVO aliTradePayVO) {
        logger.info("===========支付宝扫码支付============");
        //构建参数
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        String current = UUIDUtils.getRandomNumber(ORDERNUMBER);
        logger.info("订单号 : {}", current);
        model.setOutTradeNo(current);//商户订单号，需要保证不重复
        model.setTotalAmount(aliTradePayVO.getAmount().toString());//订单金额
        model.setSubject("支付宝扫码支付");//订单标题
        model.setStoreId(aliTradePayVO.getStoreId());//商户门店编号
        model.setTimeoutExpress(EXPIRE);//超时时间
        //构建请求
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        request.setReturnUrl(aliPayProperties.getReturnUrl());
        request.setNotifyUrl(aliPayProperties.getNotyfyUrl());
        request.setBizModel(model);
        //发起请求
        try {
            String body = aliPayApiConfig.getAliPayClient().execute(request).getBody();
            logger.info("调用成功 : {}", body);
            JSONObject jsonObject = JSON.parseObject(body);
            String objectString = jsonObject.getString("alipay_trade_precreate_response");
            JSONObject json = JSON.parseObject(objectString);
            if ("10000".equals(json.getString("code"))) {
                return json.getString("qr_code");
            }
            return json.getString("sub_msg");
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝扫码支付失败");
        }
    }

    /**
     * 退款 :
     *      注意 : 如果一个订单已经退款成功后
     *            同一个订单再次请求该接口依旧会返回退款成功信息
     *            该信息是第一次退款成功的信息(详见body信息里的gmt_refund_pay的值 其时间是第一次退款时间)
     * @param aliPayRefundVO
     */
    @Override
    public String tradeRefund(AliPayRefundVO aliPayRefundVO) {
        logger.info("===========支付宝退款============");
        //退款参数
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo(aliPayRefundVO.getOutTradeNo());//支付时传入的订单号
        model.setTradeNo(aliPayRefundVO.getTradeNo());//支付返回的支付宝交易号
        model.setRefundAmount(aliPayRefundVO.getAmount().toString());//退款金额
        model.setRefundReason("支付宝退款");//商品描述
        if ("1".equals(aliPayRefundVO.getFlag())) {
            //标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传 传入一个随机数
            model.setOutRequestNo(UUIDUtils.getRandomNumber(10));
        }
        //构建请求
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        request.setBizModel(model);
        AlipayTradeRefundResponse response =null;
        try {
            response = aliPayApiConfig.getAliPayClient().execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BusinessException("支付宝退款失败");
        }
        if (response.isSuccess()){
            logger.info("成功信息 : {}",response.getBody());
            return "退款成功";
        }else {
            logger.error("失败信息 : {}",response.getBody());
            throw new BusinessException(response.getSubMsg());
        }
    }

    /**
     * 交易订单查询
     *
     * @param aliPayRefundVO
     * @return
     */
    @Override
    public String tradeQuery(AliPayRefundVO aliPayRefundVO) {
        logger.info("===========交易订单查询============");
        //构建请求参数
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(aliPayRefundVO.getOutTradeNo());//订单号
        model.setTradeNo(aliPayRefundVO.getTradeNo());//交易号
        //构建请求
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizModel(model);
        //发起请求
        AlipayTradeQueryResponse response = null;
        try {
            response = aliPayApiConfig.getAliPayClient().execute(request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            throw new BusinessException("交易订单查询失败");
        }
        if (response.isSuccess()){
            logger.info("成功信息 : {}",response.getBody());
            return response.getBody();
        }else {
            logger.error("失败信息 : {}",response.getBody());
            throw new BusinessException(response.getSubMsg());
        }
    }

}
